/*
 *  Copyright 2011 Arngrimur Bjarnason 
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
 

package org.arngrimur.deviationtable;

import java.util.ArrayList;

import org.arngrimur.deviationtable.R;
import org.arngrimur.deviationtable.R.id;
import org.arngrimur.deviationtable.R.layout;
import org.arngrimur.deviationtable.R.menu;
import org.arngrimur.deviationtable.R.string;
import org.arngrimur.deviationtable.activity.AddCompass;
import org.arngrimur.deviationtable.activity.AddCompassDegree;
import org.arngrimur.deviationtable.activity.DeleteCompass;
import org.arngrimur.deviationtable.compass.Compass;
import org.arngrimur.deviationtable.db.DataModel;
import org.arngrimur.deviationtable.degree.AbstractDegree;
import org.arngrimur.deviationtable.degree.EmptyDegree;
import org.arngrimur.deviationtable.degree.IDegreeFactory;
import org.arngrimur.deviationtable.degree.ReferenceDegree;
import org.arngrimur.deviationtable.view.CompassDisplayString;
import org.arngrimur.deviationtable.view.ReferenceDisplayString;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.database.Cursor;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

public class DeviationTableActivity extends Activity {
	/**
	 * Size of header
	 */
	private static final float HEADER_TEXT_SIZE = 18.0f;

	private DataModel dataModel = null;
	private String logTag = "DEVIATAION_TABLE_ACTIVITY";
	private MenuItem delete = null;
	private Menu menu = null;
	private Button addDegree = null;
	private TextView gpsCompassValue = null;
	private TableLayout tableHeader = null;
	private TableLayout tableContent = null;
	private ScrollView scrollView = null;
	private boolean lightGrayBackroundRow = false;
	private Context context = null;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		this.context = this;
		this.dataModel = new DataModel(this);

		setContentView(R.layout.main);
		this.addDegree = (Button) findViewById(R.id.addDegreeButton);
		this.addDegree.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				ReferenceDegree input = new ReferenceDegree(Double
						.parseDouble(gpsCompassValue.getText().toString()),
						dataModel.getReferenceCompass());
				ReferenceDisplayString reference = new ReferenceDisplayString(
						context, input);
				dataModel.addReferenceValue(reference);
				

				for (Compass c : dataModel.getCompasses()) {
					Intent addCompassValue = new Intent(context,
							AddCompassDegree.class);
					addCompassValue.putExtra(AddCompassDegree.COMPASS_NAME_KEY,
							c.getName());
					addCompassValue.putExtra(AddCompassDegree.REFERENCE_VALUE,
							input.toString());
					startActivityForResult(addCompassValue,
							AddCompassDegree.REQUEST_CODE);
				}
				updateUI();
			}
		});



		this.gpsCompassValue = (TextView) findViewById(R.id.numericalInputField);
		this.tableHeader = (TableLayout) findViewById(R.id.compassTable);
		this.scrollView = (ScrollView) findViewById(R.id.contentScroller);
		this.tableContent = (TableLayout) findViewById(R.id.tableContent);

		this.scrollView.setScrollbarFadingEnabled(true);
		this.scrollView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);

		this.tableHeader.setStretchAllColumns(true);
		this.tableContent.setStretchAllColumns(true);

		//this.dataModel.readMappedValues

		this.updateUI();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.main_menu, menu);
		this.menu = menu;
		return true;
	}

	@Override
	/**
	 * {@inheritDoc}
	 * @return true if operation succeded
	 */
	public boolean onOptionsItemSelected(MenuItem item) {

		switch (item.getItemId()) {
		case R.id.add_compass:
			addCompass();
			break;
		case R.id.delete_compass:
			deleteCompass();
		default:
			return false;
		}
		return true;
	}

	/**
	 * Creates a new Activity to delete a compass from known compasses
	 */
	private void deleteCompass() {
		Intent deleteCompass = new Intent(this, DeleteCompass.class);
		String[] input = new String[this.dataModel.getCompasses().size()];
		int i = 0;
		for (Compass c : this.dataModel.getCompasses()) {
			input[i++] = c.getName();
		}
		deleteCompass.putExtra(getString(R.string.deletecompassvalues), input);
		startActivityForResult(deleteCompass, DeleteCompass.REQUEST_CODE);
	}

	/**
	 * Creates a new Activity to add a compass to list of known compasses.
	 */
	private void addCompass() {
		Log.d(logTag, "Starting activity AddCompass");
		Intent addCompass = new Intent(this, AddCompass.class);
		startActivityForResult(addCompass, AddCompass.REQUEST_CODE);
	}

	/**
	 * Handle callback from other activities.
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (resultCode == Activity.RESULT_OK) {
			Compass compass = null;
			switch (requestCode) {
			case DeleteCompass.REQUEST_CODE:
				this.dataModel.deleteCompass(data.getIntExtra(DeleteCompass.DELETE_INDEX,
						this.dataModel.getCompasses().size() - 1));
				enableDeleteMenuItem();
				break;
			case AddCompass.REQUEST_CODE:
				compass = new Compass(data.getExtras().getString(
						AddCompass.COMPASS_NAME));
				this.dataModel.addCompass(compass);
				enableDeleteMenuItem();
				break;
			case AddCompassDegree.REQUEST_CODE:
				String compassName = data.getExtras().getString(
						AddCompassDegree.COMPASS_NAME_KEY);

				String reference = data
						.getStringExtra(AddCompassDegree.REFERENCE_VALUE);

				IDegree deg = IDegreeFactory.getIDegree(data.getExtras()
						.getDouble(AddCompassDegree.NEW_COMPASS_DEGREE),
						this.dataModel.getCompassFromName(compassName),
						(ReferenceDegree)this.dataModel.getReferenceValue(reference));

				for (Compass c : this.dataModel.getCompasses()) {
					if (compassName.equals(c.getName())) {
						c.setReadValue(
								this.dataModel.getReferenceValue(reference),
								deg);
						this.dataModel.insertIntoDatabase(deg, reference, c);
						break;
					}
				}

				break;
			default:
				return;
			}
			updateUI();
		}
	}

	

	/**
	 * Enables / disable the menu item 'Delete'.
	 */
	private void enableDeleteMenuItem() {
		if (this.dataModel.getCompasses().size() > 0) {
			this.delete = menu.getItem(1);
			this.delete.setEnabled(true);
		} else {
			if (this.delete != null) {
				this.delete.setEnabled(false);
			}
		}
	}

	/**
	 * Updates the GUI
	 */
	private void updateUI() {
		this.tableHeader.removeAllViews();
		this.tableContent.removeAllViews();
		int cols = this.dataModel.getCompasses().size() + 1;
		String[] rowValues = new String[cols];
		rowValues[0] = "Gps";
		for (int i = 1; i < cols; i++) {
			rowValues[i] = ((ArrayList<Compass>) this.dataModel.getCompasses())
					.get(i - 1).getName();
		}
		addRow(this.tableHeader, rowValues);

		ArrayList<DisplayDegree> dataRows = new ArrayList<DisplayDegree>();
		for (AbstractDegree gpsValue : this.dataModel.getRefenceValues()) {
			dataRows.add(new ReferenceDisplayString(this.context, gpsValue));
			for (int i = 0; i < this.dataModel.getCompasses().size(); i++) {
				dataRows.add(new CompassDisplayString(this.context,
						findRowValueForCompass(
								((ArrayList<Compass>) this.dataModel
										.getCompasses()).get(i), gpsValue)));
			}
			addRow(this.tableContent, dataRows);
			dataRows.clear();
		}

		for (int i = 0; i < this.tableHeader.getChildCount(); i++) {
			try {
				TableRow header = (TableRow) this.tableHeader.getChildAt(i);
				for (int j = 0; j < header.getChildCount(); j++) {
					TextView textView = (TextView) header.getChildAt(j);
					textView.setTextSize(HEADER_TEXT_SIZE);
				}
			} catch (ClassCastException e) {
				// EMPTY
			}

		}
		// Clean entries and set default values
		this.lightGrayBackroundRow = false;
		this.gpsCompassValue.setText("");
	}

	/**
	 * @param i
	 *            Index of compass in this.compassValues
	 * @param degree
	 *            The degree to find
	 * @return The given recorded degree for the given input or '---' if not
	 *         found
	 */
	private IDegree findRowValueForCompass(Compass compass, IDegree degree) {
		IDegree found = compass.getReadValue(degree);
		if (found == null) {
			return new EmptyDegree(compass);
		} else {
			return found;
		}
	}

	/**
	 * @param tableContent
	 *            The table to populate
	 * @param dataRows
	 *            The data of the row of the table
	 */
	private void addRow(TableLayout tableContent, ArrayList<DisplayDegree> dataRows) {
		TableRow row = new TableRow(this);

		for (DisplayDegree rowItem : dataRows) {
			row.addView((TextView) rowItem);
		}

		this.setRowBackground(row);
		tableContent.addView(row);
	}

	/**
	 * @param table
	 *            The table where to add the string
	 * @param rowValues
	 *            The string content to write
	 */
	private void addRow(TableLayout table, String[] rowValues) {
		TableRow row = new TableRow(this);

		for (String rowValue : rowValues) {
			TextView view = new TextView(this);
			view.setText(rowValue);
			view.setTextColor(ColorStateList.valueOf(Color.BLACK));
			view.setGravity(Gravity.CENTER);
			row.addView(view);
		}
		table.addView(row);
		this.setRowBackground(row);
	}

	/**
	 * Set the background color of a row to white or lightgray
	 * 
	 * @param row
	 *            The row to set the color
	 */
	private void setRowBackground(TableRow row) {
		if (this.lightGrayBackroundRow) {
			row.setBackgroundColor(Color.LTGRAY);
		} else {
			row.setBackgroundColor(Color.WHITE);
		}
		this.lightGrayBackroundRow = !this.lightGrayBackroundRow;
	}

	/**
	 * Removes a reference value.
	 * 
	 * @param degree
	 */
	public void removeReference(IDegree degree) {
		this.dataModel.removeReferenceValue(degree);
		this.updateUI();
	}

	/**
	 * @param degree Degree to change
	 * @param reference The reference value 
	 * @param compass The compass
	 */
	//TODO Ensure that value is changed in database
	public void updateCompassValue(IDegree degree, IDegree reference, 
			Compass compass) {
		EmptyDegree e = new EmptyDegree(compass);
		compass.removeReadValue(reference);
		compass.setReadValue(reference, e);
		this.updateUI();
	}

}